package br.com.ucb.projFinal.beans;
import java.util.ArrayList;

public class TLista implements ILista {
        // ATRIBUTOS---------------
        private static IElemento primero;
        private static int cantidadElementos;
        // ------------------------

        // ENCAPSULAMOS------------------
        public IElemento getPrimero() {
                return primero;
        }

        public void setPrimero(IElemento primero) {
                this.primero = primero;
        }

        // ------------------------------

        // METODOS-----------------------
        /**
         * Metodo: constructor
         * 
         * Funcion: El objetivo del constructor es el de inicializar un objeto de la
         * clase TLista cuando éste es creado. Asignaremos los valores iniciales:
         * primero.
         * 
         * @param primero - Elemento a colocar en el primer lugar de la lista. 
         * 
         */
        public TLista(IElemento primero) {
                cantidadElementos=0 ;
                this.primero = primero;
        }

        /**
         * Metodo: constructor
         * 
         * Funcion: El objetivo del constructor es el de inicializar un objeto de la
         * clase TLista cuando éste es creado.
         */
        public TLista(){
            primero = null;
            cantidadElementos=0 ;

    }
    
        /**
         * Metodo: insertarAlFinal
         * 
         * Funcion: Inserta elemento al final de la lista
         * 
         * @author grupo4
         */
        @Override
        public boolean insertarAlFinal(IElemento elemento) {
                IElemento eleActual;
                eleActual = primero;
                if (esVacia()) {
                        primero = elemento;
                        cantidadElementos++;
                        return (primero == elemento);
                }
                while (eleActual.getSiguiente() != null) {
                        eleActual = eleActual.getSiguiente();
                }
                eleActual.setSiguiente(elemento);
                cantidadElementos++;
                return (eleActual.getSiguiente() == elemento);
        }

        /**
         * Metodo: esVacia
         * 
         * Funcion: verifica si la lista es o no vacia
         * 
         * @return
         *  - TRUE si la lista es vacia
         *  - FALSE si la lista no es vacia
         */
        public boolean esVacia() {
                return (primero == null);
        }

        /**
         * Metodo: insertarAlPrincipio
         */
        @Override
        public boolean insertarAlPrincipio(IElemento elemento) {
                elemento.setSiguiente(primero);
                cantidadElementos++;
                primero = elemento;
                return (primero == elemento);
        }

        /**
         * Metodo: buscar
         * 
         * Funcion: Método que busca en la lista un elemento por su etiqueta, trae el primer elemento que encuentra con esa etiqueta.
         * Verificamos que la etiqueta sea valida y que la lista no este vacía, si la etiqueta a buscar es la del primer elemento retornamos primero, 
         * de lo contario recorremos la lista hasta encontrar la etiqueta (utilizando el método anterior)
         * 
         * @param clave - Clave a buscar
         * @return elemento buscado si está, si no está null. 
         */
        @SuppressWarnings({ "rawtypes", "unchecked" })
        @Override
        public IElemento buscar(int clave) {
                IElemento eleActual= primero; 
                if (esVacia()||clave == 0) {
                        return null;
                }

                while (eleActual != null
                                && eleActual.getEtiqueta()!= clave ) {
                        eleActual = eleActual.getSiguiente();
                }

                return eleActual;
        }

        
        /**
         *Metodo: eliminar
         *
         *Funcion: elimina un elemento de la lista 
         *
         *@param clave - clave a eliminar
         *@return 
         * - TRUE si tuvo éxito
         * - FALSE si no tuvo éxito
         */
    	@Override
    	public IElemento eliminar(int unaEtiqueta) {

    		if (primero != null && unaEtiqueta != 0) {
    			if (primero.getEtiqueta()==unaEtiqueta){
    				cantidadElementos--;
    				return quitarPrimero();
    			}
    			else{
    				IElemento eleAnt = anterior(unaEtiqueta);
    				if (eleAnt == null )
    					return null;
    				else{
    					IElemento elementoADevolver = eleAnt.getSiguiente();
    					eleAnt.setSiguiente(elementoADevolver.getSiguiente());
    					elementoADevolver.setSiguiente(null);
    					cantidadElementos--;
    					return elementoADevolver;
    				}
    			}
    		}
    		return null;
    	}
    	
    	public IElemento quitarPrimero() {
    		System.out.println("aaaaaaaaa");
    		if (primero == null)
    			return primero;
    		else
    		{
    			IElemento elementoADevolver  = primero; 
    			primero = primero.getSiguiente();
    			elementoADevolver.setSiguiente(null);
    			
    			cantidadElementos--;
    			
    			return elementoADevolver;	
    		}
    	}
    	
    	/**
    	 * Método que obtiene dada una etiqueta 
    	 * el elemento anterior
    	 */
    	public IElemento anterior(int unaEtiqueta) {
    		//si la lista no es vacia y  la etiqueta es distinta de nulo
    		//itera hasta obtener en eleAct la etiqueta esperada y guarda 
    		//sucesivamente el anterior a devolver
    		if (primero != null && unaEtiqueta != 0){
    			IElemento eleAnt = null;
    			IElemento eleAct = primero;
    			while (eleAct != null && eleAct.getEtiqueta()!=unaEtiqueta){
    				eleAnt = eleAct;
    				eleAct = eleAct.getSiguiente();
    			}
    				//si encuentra la etiqueta devuelve el elemento anterior
    			if (eleAct != null)
    				return eleAnt;
    			else
    				//sino devuelve nulo
    				return null;
    		}
    		else
    			//condiciones en que o la lista es vacía o la etiqueta es nula
    			return null;
    	}

        /**
         * Metodo: insertarOrdenado
         * 
         * Funcion: inserta un elemento en la lista en forma ordenada 
         * 
         * @param elemento: elemento a insertar
         * @return resultado de la operacion
         */
        public boolean insertarOrdenado(IElemento elemento) {
                if (elemento == null){
                        return false;
                }
                else if (primero == null || (primero.getEtiqueta()>elemento.getEtiqueta())){
                        return insertarAlPrincipio(elemento);
                }
                else{
                        IElemento elementoAnterior = null;
                        IElemento elementoActual = primero;
                        while (elementoActual != null && (elementoActual.getEtiqueta()<elemento.getEtiqueta())){
                                elementoAnterior = elementoActual;
                                elementoActual = elementoActual.getSiguiente();
                        }
                        elementoAnterior.setSiguiente(elemento);
                        elemento.setSiguiente(elementoActual);
                        cantidadElementos++;
                        return true;
                }
        }
        
        /**
         * Metodo: imprimirElementos
         * 
         * Funcion: devuelve un string con todos los elementos de la lista. 
         */
        public String ImprimirElementos() {
        	//String auxiliar para devolver
    		String sResultado = "";
    		
    		//si la lista es vacia devuelve el string vacío
    		if (primero == null)
    			return sResultado;
    		//elemento auxiliar para iterar en la lista
    		IElemento eleAct = primero;
    		
    		//mientras el elemento para iterar sea distinto de 
    		//nulo se concatenan las etiquetas del eleAct
    		while (eleAct != null){
    			sResultado += eleAct.getEtiqueta() ;
    			eleAct = eleAct.getSiguiente();
    			//si no es el ultimo agrega separador
    			if (eleAct != null)
    				sResultado +="-";
    		}
    		//devuelve string concatenado de etiquetas
    		return sResultado;
        }

        /**
         * Metodo: Eliminar Duplicados
         * 
         * Funcion: Elimina los duplicados de la lista, de forma tal que crea una
         * lista auxiliar, y va insertando los elementos verificando que dichos
         * elementos no se encuentren ya en la lista auxiliar y los va eliminando de
         * la lista original cuando la lista original quede vacia, referenciamos al
         * primer objeto de nuestra lista original como el primer objeto de la lista
         * auxiliar sin duplicados.
         * 
         * @author group 4
         * 
         * @return boolean
         */
        public boolean eliminarDuplicados() {

        	IElemento otroElemento;
        	IElemento unElemento = primero;
        	TLista listaAux = new TLista(primero);
        	
        	while (unElemento != null){
        		 otroElemento = unElemento.getSiguiente();
        		 while (otroElemento != null){
        			if(otroElemento.getEtiqueta()== unElemento.getEtiqueta()){
        				
        				
        				
        				eliminar(otroElemento);
        				
        				otroElemento = otroElemento.getSiguiente();
        				
        			}
        			else
        				otroElemento = otroElemento.getSiguiente();
        		 }
        		 unElemento = unElemento.getSiguiente();
        	}
        	return true;

        }

        public IElemento eliminar(IElemento elemento){
        	if (buscar(elemento.getEtiqueta()) == null)
        		return null;
        	else{
        		IElemento eleActual = primero.getSiguiente();
        		IElemento eleAnterior = primero;
        		if (primero == elemento){
        			IElemento ele = primero; 
        			primero = primero.getSiguiente();
        			return ele;
        		}
        		while (eleActual != null && eleActual != elemento){
        			eleAnterior = eleActual;
        			eleActual = eleActual.getSiguiente();
        		}
        		if (eleActual == elemento){
        			eleAnterior.setSiguiente(eleActual.getSiguiente());
        		}
        	}
        
        	return null;
        }

        /**
         * Metodo: obetenerCantidadElementos
         * 
         * Funcion: control, devuelve la cantidad de elementos en la lista
         * 
         * @return cantidad de elementos en la lista. 
         */
        public int obtenerCantidadElementos() {
                return cantidadElementos;
        }
        
        /**
    	 * Funcion auxiliar que dado una ruta en el string por parametro, 
    	 * busca las palabras en el archivo de la ruta y las devuelve 
    	 * filtradas en un vector de Strings 
    	 * @param archivo ruta del archivo
    	 * @return palabras del .txt en un array de strings
    	 * null en caso de no encontrar la ruta
    	 */
    	public static String[] devolverPalabras(String archivo){

    		ManejadorArchivosGenerico mag = new ManejadorArchivosGenerico();
    		String[] lineas = mag.leerArchivo(archivo);
    		
    		if (lineas == null)
    			return null;
    		
    		ArrayList<String> todasLasPalabras = new ArrayList<String>();
    		
    		for (int i = 0; i < lineas.length; i++){			
    			String[] palabras = lineas[i].toString().split(" ");

    			for (int j = 0; j < palabras.length; j++){
    				
    				palabras[j] = filtrarPalabra(palabras[j]);
    				
    				if (palabras[j].length() > 0)
    					todasLasPalabras.add(palabras[j]);

    			}
    		}
    		System.out.println(todasLasPalabras.toString());
    		return todasLasPalabras.toArray(new String[todasLasPalabras.size()]);		
    	}

    	/**
    	 * Metodo encargado de filtrar un texto, dejando solamente letras validas.-
    	 * @param unaPalabra Palabra a evaluar
    	 * @return Cadena de caracteres limpia
    	 */
    	public static String filtrarPalabra(String unaPalabra) {
    		return unaPalabra;
    	}

    	/**
    	 * Metodo encargado de guardar un archivo.
    	 * @param nombreCompletoArchivo
    	 * @return
    	 */
    	public static boolean guardarArchivo(String nombreCompletoArchivo){
    		ManejadorArchivosGenerico man = new ManejadorArchivosGenerico();
    		String[] listaLineasArchivo = etiquetasToArray();
    		man.escribirArchivo(nombreCompletoArchivo, listaLineasArchivo);
    		return true;
    				
    	}
    	
   	 /**
   	  * Metodo que carga un vector con las etiquietas de la lista
   	  */
   	private static String[] etiquetasToArray() {
   		String[] vector = new String[cantidadElementos];
   		
   		if (primero == null)
   			return vector;
   		else{
   			IElemento elementoActual = primero;
   			Integer pos = 0;
   			while (elementoActual != null){
   				vector[pos] = String.valueOf(elementoActual.getEtiqueta()) ;
   				pos++;
   				elementoActual = elementoActual.getSiguiente();
   			}
   		}
   			
   		return vector;
   	}
}
